package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domin.dto.LearningPlanDTO;
import com.tianji.learning.domin.po.LearningLesson;
import com.tianji.learning.domin.po.LearningRecord;
import com.tianji.learning.domin.vo.LearningLessonVO;
import com.tianji.learning.domin.vo.LearningPlanPageVO;
import com.tianji.learning.domin.vo.LearningPlanVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生课程表 服务实现类
 * </p>
 *
 * @author author
 * @since 2023-08-26
 */
@RequiredArgsConstructor
@Transactional
@Service
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {


    private final CourseClient courseClient;
    private final CatalogueClient catalogueClient;

    private final LearningRecordMapper learningRecordMapper;

    @Override
    public void addUserLessons(Long userId, List<Long> courseIds) {
        //远程调用课程服务，根据课程id返回课程
        List<CourseSimpleInfoDTO> clientSimpleInfoList = courseClient.getSimpleInfoList(courseIds);
        //远程调用课程服务，根据课程id返回小节id
        //封装po
        List<LearningLesson> lessons = new ArrayList<>();
        for (CourseSimpleInfoDTO courseSimpleInfoDTO : clientSimpleInfoList) {
            LearningLesson lesson = new LearningLesson();
            lesson.setUserId(userId);
            lesson.setCourseId(courseSimpleInfoDTO.getId());
            LocalDateTime now = LocalDateTime.now();
            lesson.setCreateTime(now);
            Integer validDuration = courseSimpleInfoDTO.getValidDuration();
            if (validDuration != null) {

                lesson.setExpireTime(now.plusMonths(validDuration));
            }
            lessons.add(lesson);
        }
        //批量添加课程表

        saveBatch(lessons);
    }

    @Override
    public PageDTO<LearningLessonVO> queryMyLessons(PageQuery query) {

        Long userId = UserContext.getUser();


        Page<LearningLesson> page = lambdaQuery().eq(LearningLesson::getUserId, userId).page(query.toMpPage("latest_learn_time", false));

        List<LearningLesson> learningLessonList = page.getRecords();
        if (CollectionUtils.isEmpty(learningLessonList)) {
            return PageDTO.empty(page);
        }

        List<Long> courseIds = learningLessonList.stream().map(LearningLesson::getCourseId).collect(Collectors.toList());
        List<CourseSimpleInfoDTO> courseClientSimpleInfoList = courseClient.getSimpleInfoList(courseIds);

        if (CollectionUtils.isEmpty(courseClientSimpleInfoList)) {
            throw new BizIllegalException("课程为空");
        }

        Map<Long, CourseSimpleInfoDTO> courseSimpleInfoDTOMap = courseClientSimpleInfoList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));

        List<LearningLessonVO> lessonVOList = learningLessonList.stream().map(learningLesson -> {
            LearningLessonVO learningLessonVO = BeanUtils.copyBean(learningLesson, LearningLessonVO.class);
            CourseSimpleInfoDTO infoDTO = courseSimpleInfoDTOMap.get(learningLesson.getCourseId());
            learningLessonVO.setCourseName(infoDTO.getName());
            learningLessonVO.setCourseCoverUrl(infoDTO.getCoverUrl());
            learningLessonVO.setSections(infoDTO.getSectionNum());
            return learningLessonVO;
        }).collect(Collectors.toList());


        return PageDTO.of(page, lessonVOList);
    }

    @Override
    public LearningLessonVO queryMyCurrentLesson() {
        //获取用户Id
        Long userId = 2L;
        //根据当前用户 查询一条用户最近一次学习的课程 状态为学习中
        LearningLesson learningLesson = lambdaQuery().eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getStatus, LessonStatus.LEARNING)
                .orderByDesc(LearningLesson::getLatestLearnTime).last("limit 1").one();

        if (learningLesson == null) {
            return null;
        }
        //通过远程调用获取 课程封面、名称、课程章节数量
        CourseFullInfoDTO courseInfo = courseClient.getCourseInfoById(learningLesson.getCourseId(), false, false);
        if (courseInfo == null) {
            throw new BizIllegalException("课程为空");
        }
        //根据最近一次学习的小节id 通过远程调用获取 最近一次学习的小节名称、小节序号
        List<CataSimpleInfoDTO> cataSimpleInfoDTOS = catalogueClient.batchQueryCatalogue(CollUtils.singletonList(learningLesson.getLatestSectionId()));

        if (CollectionUtils.isEmpty(cataSimpleInfoDTOS)) {
            throw new BizIllegalException("小节为空");
        }
        CataSimpleInfoDTO cataSimpleInfoDTO = cataSimpleInfoDTOS.get(0);
        //查询当前用户的中课程数
        Long count = lambdaQuery().eq(LearningLesson::getUserId, userId).count();
        //封装PO对象到VO 返回
        LearningLessonVO learningLessonVO = BeanUtils.copyBean(learningLesson, LearningLessonVO.class);

        learningLessonVO.setLatestSectionName(cataSimpleInfoDTO.getName());
        learningLessonVO.setLatestSectionIndex(cataSimpleInfoDTO.getCIndex());

        learningLessonVO.setCourseCoverUrl(courseInfo.getCoverUrl());
        learningLessonVO.setCourseName(courseInfo.getName());
        learningLessonVO.setSections(courseInfo.getSectionNum());
        learningLessonVO.setCourseAmount(Math.toIntExact(count));


        return learningLessonVO;
    }

    @Override
    public LearningLessonVO queryMyLessonStatus(Long courseId) {
        //获取当前用户
        Long userId = UserContext.getUser();

        //根据当前用户Id、课程Id 获取课程表
        LearningLesson learningLesson = lambdaQuery().eq(LearningLesson::getUserId, userId).eq(LearningLesson::getCourseId, courseId).one();
        if (learningLesson == null) {
            return null;
        }
        //PO封装VO 返回
        LearningLessonVO learningLessonVO = new LearningLessonVO();
        learningLessonVO.setCourseId(courseId);
        learningLessonVO.setStatus(learningLesson.getStatus());
        learningLessonVO.setLearnedSections(learningLesson.getLearnedSections());
        learningLessonVO.setCreateTime(learningLesson.getCreateTime());
        learningLessonVO.setExpireTime(learningLesson.getExpireTime());
        learningLessonVO.setPlanStatus(learningLesson.getPlanStatus());
        return learningLessonVO;
    }

    @Override
    public Long checkCourseAvailability(Long courseId) {
        //获取当前用户Id
        Long userId = UserContext.getUser();
        //根据用户id、课程id查询课表
        LearningLesson learningLesson = lambdaQuery().eq(LearningLesson::getUserId, userId).eq(LearningLesson::getCourseId, courseId).one();
        if (learningLesson == null) {
            return null;
        }
        //判断是否过期
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime expireTime = learningLesson.getExpireTime();
        if (expireTime != null && now.isAfter(expireTime)) {
            return null;
        }
        //返回
        return learningLesson.getId();
    }

    @Override
    public Integer countLearningLessonByCourse(Long courseId) {
        //根据课程id 查询课程表
        Long count = lambdaQuery().eq(LearningLesson::getCourseId, courseId).count();
        //返回
        return Math.toIntExact(count);
    }

    @Override
    public void createLessonPlans(LearningPlanDTO dto) {
        //获取当前用户
        Long userId = UserContext.getUser();
        //判断课表是否存在
        LearningLesson learningLesson = lambdaQuery().eq(LearningLesson::getUserId, userId).eq(LearningLesson::getCourseId, dto.getCourseId()).one();
        if (learningLesson == null) {
            throw new BizIllegalException("课表不存在");
        }
        //更新课表
        boolean update = lambdaUpdate().set(LearningLesson::getWeekFreq, dto.getFreq()).set(LearningLesson::getPlanStatus,PlanStatus.PLAN_RUNNING).eq(LearningLesson::getId, learningLesson.getId()).update();
        if (!update) {
            throw new DbException("更新学习计划失败");
        }
    }

    @Override
    public LearningPlanPageVO queryMyPlans(PageQuery pageQuery) {
        //获取当前登录用户
        Long userId = UserContext.getUser();
        //查询课表获取、某课程本周计划学习小节数量、某课程本周已经学习小节数量、本周实际学习小节数量、最后学习时间
        //本周计划学习小节数
        QueryWrapper<LearningLesson> wrapper = new QueryWrapper<>();
        wrapper.select("sum(week_freq) as plansTotal");
        wrapper.eq("user_id", userId);
        wrapper.in("status", LessonStatus.NOT_BEGIN, LessonStatus.LEARNING);
        wrapper.eq("plan_status", PlanStatus.PLAN_RUNNING);
        int plansTotal = Integer.parseInt(getMap(wrapper).get("plansTotal").toString());
        //本周实际完成小节
        LocalDate now = LocalDate.now();
        LocalDateTime weekBeginTime = DateUtils.getWeekBeginTime(now);
        LocalDateTime weekEndTime = DateUtils.getWeekEndTime(now);

        // 执行查询并获取结果数量
        Long weekFinishNumber = learningRecordMapper.selectCount(userId, true, weekBeginTime, weekEndTime);


        //查询课表
        Page<LearningLesson> page = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getPlanStatus, true)
                .in(LearningLesson::getStatus, LessonStatus.NOT_BEGIN, LessonStatus.LEARNING)
                .page(pageQuery.toMpPage("latest_learn_time", false));
        List<LearningLesson> lessons = page.getRecords();
        if (CollectionUtils.isEmpty(lessons)) {
            LearningPlanPageVO vo = new LearningPlanPageVO();
            vo.setTotal(0L);
            vo.setPages(0L);
            vo.setList(CollUtils.emptyList());
            return vo;
        }
        List<Long> courseIds = lessons.stream().map(LearningLesson::getCourseId).collect(Collectors.toList());

        //查询课程

        List<CourseSimpleInfoDTO> clientSimpleInfoList = courseClient.getSimpleInfoList(courseIds);
        if (CollectionUtils.isEmpty(clientSimpleInfoList)) {
            throw new DbException("查询课程失败");
        }
        Map<Long, CourseSimpleInfoDTO> courseSimpleInfoDTOMap = clientSimpleInfoList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, o -> o));

        //查询学习记录
        QueryWrapper<LearningRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("lesson_id as lessonId", "count(*) as userId");
        queryWrapper.eq("user_id", userId);
        queryWrapper.eq("finished", true);
        queryWrapper.between("finish_time", weekBeginTime, weekEndTime);
        queryWrapper.groupBy("lesson_id");
        List<LearningRecord> learningRecords = learningRecordMapper.selectList(queryWrapper);
        Map<Long, Long> recordMap = null;
        if (!CollectionUtils.isEmpty(learningRecords)) {
            //getUserId是Count的临时字段
            recordMap = learningRecords.stream().collect(Collectors.toMap(LearningRecord::getLessonId, LearningRecord::getUserId));
        }

        //封装VO返回
        LearningPlanPageVO planPageVO = new LearningPlanPageVO();
        planPageVO.setWeekTotalPlan(plansTotal);
        planPageVO.setWeekFinished(Integer.parseInt(String.valueOf(weekFinishNumber)));
        List<LearningPlanVO> planVOS = new ArrayList<>();

        for (LearningLesson learningLesson : lessons) {

            LearningPlanVO learningPlanVO = BeanUtils.copyBean(learningLesson, LearningPlanVO.class);
            Long courseId = learningLesson.getCourseId();
            CourseSimpleInfoDTO courseSimpleInfoDTO = courseSimpleInfoDTOMap.get(courseId);
            if (courseSimpleInfoDTO != null) {
                learningPlanVO.setCourseId(courseSimpleInfoDTO.getId());
                learningPlanVO.setCourseName(courseSimpleInfoDTO.getName());
                learningPlanVO.setSections(courseSimpleInfoDTO.getSectionNum());
            }
            if(recordMap!=null){

                learningPlanVO.setWeekLearnedSections(recordMap.getOrDefault(learningLesson.getId(), 0L).intValue());
            }else {
                learningPlanVO.setWeekLearnedSections(0);
            }

            planVOS.add(learningPlanVO);
        }

        planPageVO.setPages(page.getPages());
        planPageVO.setTotal(page.getTotal());
        planPageVO.setList(planVOS);
        return planPageVO;
    }
}
